﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace System.Web.Mvc.Html
{

    /// <summary>
    /// 为HtmlHelper类添加扩展方法
    /// </summary>
    public static class HtmlHelperExtensions
    {
        #region Pagger

        /// <summary>
        /// Html分页扩展方法
        /// </summary>
        /// <param name="helper">HtmlHelper对象</param>
        /// <param name="rowCount">分页数据的总行数</param>
        /// <param name="pageIndex">当前分页索引，从0开始</param>
        /// <param name="pageSize">每页的显示个数</param>
        /// <param name="ajaxPaggerFormat">生成HTML分页对象的对象</param>
        /// <returns></returns>
        public static MvcHtmlString Pagger(this HtmlHelper helper, int rowCount, int pageIndex, int pageSize, IPaggerFormat htmlPaggerFormat)
        {

            if (htmlPaggerFormat == null)
            {
                htmlPaggerFormat = new HtmlPrevNextPaggerFormat();
            }
            (htmlPaggerFormat as HtmlPaggerFormat).Helper = helper;

            string controllerName = helper.ViewContext.RouteData.Values["controller"].ToString();
            string actionName = helper.ViewContext.RouteData.Values["action"].ToString();
            RouteValueDictionary routeValues = helper.ViewContext.RouteData.Values;

            string s = htmlPaggerFormat.GetFormatString(actionName, controllerName, routeValues, rowCount, pageIndex, pageSize);
            s = String.Format("<div class=\"pagger-container\">{0}</div>", s);
            return new MvcHtmlString(s);
        }

        /// <summary>
        /// Html分页扩展方法
        /// </summary>
        /// <param name="helper">HtmlHelper对象</param>
        /// <param name="rowCount">分页数据的总行数</param>
        /// <param name="pageIndex">当前分页索引，从0开始</param>
        /// <param name="pageSize">每页的显示个数</param>
        /// <param name="paggerType">分页方式</param>
        /// <param name="httpMethod">Http请求方式：GET|POST</param>
        /// <param name="buttonLabel">分页按钮Label对象</param>
        /// <returns></returns>
        public static MvcHtmlString Pagger(this HtmlHelper helper, int rowCount, int pageIndex, int pageSize, HtmlPaggerType paggerType, HttpMethod httpMethod, PageButtonLabel buttonLabel)
        {
            PageButtonLabel bl = buttonLabel == null ? PageButtonLabel.Default : buttonLabel;
            IPaggerFormat paggerFormat = null;
            switch (paggerType)
            {
                case HtmlPaggerType.Numeric:
                    paggerFormat = new HtmlNumericPaggerFormat(httpMethod)
                    {
                        PreviousLabel = bl.Previous,
                        NextLabel = bl.Next
                    };
                    break;
                default:
                    paggerFormat = new HtmlPrevNextPaggerFormat(httpMethod)
                    {
                        FirstLabel = bl.First,
                        PreviousLabel = bl.Previous,
                        NextLabel = bl.Next,
                        LastLabel = bl.Last
                    };
                    break;
            }
            return Pagger(helper, rowCount, pageIndex, pageSize, paggerFormat);
        }

        /// <summary>
        /// Html分页扩展方法，Http请求方式使用GET并使用默认的分页按钮Label
        /// </summary>
        /// <param name="helper">HtmlHelper对象</param>
        /// <param name="rowCount">分页数据的总行数</param>
        /// <param name="pageIndex">当前分页索引，从0开始</param>
        /// <param name="pageSize">每页的显示个数</param>
        /// <param name="paggerType">分页方式</param>        
        /// <returns></returns>
        public static MvcHtmlString Pagger(this HtmlHelper helper, int rowCount, int pageIndex, int pageSize, HtmlPaggerType paggerType)
        {
            return Pagger(helper, rowCount, pageIndex, pageSize, paggerType, HttpMethod.GET, PageButtonLabel.Default);
        }

        /// <summary>
        /// Html分页扩展方法，Http请求方式使用GET
        /// </summary>
        /// <param name="helper">HtmlHelper对象</param>
        /// <param name="rowCount">分页数据的总行数</param>
        /// <param name="pageIndex">当前分页索引，从0开始</param>
        /// <param name="pageSize">每页的显示个数</param>
        /// <param name="paggerType">分页方式</param>   
        /// <param name="buttonLabel">分页按钮Label对象</param>
        /// <returns></returns>
        public static MvcHtmlString Pagger(this HtmlHelper helper, int rowCount, int pageIndex, int pageSize, HtmlPaggerType paggerType, PageButtonLabel buttonLabel)
        {
            return Pagger(helper, rowCount, pageIndex, pageSize, paggerType, HttpMethod.GET, buttonLabel);
        }

        /// <summary>
        /// Html分页扩展方法，使用默认的分页按钮Label
        /// </summary>
        /// <param name="helper">HtmlHelper对象</param>
        /// <param name="rowCount">分页数据的总行数</param>
        /// <param name="pageIndex">当前分页索引，从0开始</param>
        /// <param name="pageSize">每页的显示个数</param>
        /// <param name="paggerType">分页方式</param>  
        /// <param name="httpMethod">Http请求方式：GET|POST</param>
        /// <returns></returns>
        public static MvcHtmlString Pagger(this HtmlHelper helper, int rowCount, int pageIndex, int pageSize, HtmlPaggerType paggerType, HttpMethod httpMethod)
        {
            return Pagger(helper, rowCount, pageIndex, pageSize, paggerType, httpMethod, PageButtonLabel.Default);
        }

        /// <summary>
        /// Html分页扩展方法，使用PrevNext分页方式
        /// </summary>
        /// <param name="helper">HtmlHelper对象</param>
        /// <param name="rowCount">分页数据的总行数</param>
        /// <param name="pageIndex">当前分页索引，从0开始</param>
        /// <param name="pageSize">每页的显示个数</param>        
        /// <param name="httpMethod">Http请求方式：GET|POST</param>
        /// <param name="buttonLabel">分页按钮Label对象</param>
        /// <returns></returns>
        public static MvcHtmlString Pagger(this HtmlHelper helper, int rowCount, int pageIndex, int pageSize, HttpMethod httpMethod, PageButtonLabel buttonLabel)
        {
            return Pagger(helper, rowCount, pageIndex, pageSize, HtmlPaggerType.PrevNext, httpMethod, buttonLabel);
        }

        /// <summary>
        /// Html分页扩展方法，使用PrevNext分页方式并使用默认的分页按钮Label
        /// </summary>
        /// <param name="helper">HtmlHelper对象</param>
        /// <param name="rowCount">分页数据的总行数</param>
        /// <param name="pageIndex">当前分页索引，从0开始</param>
        /// <param name="pageSize">每页的显示个数</param>
        /// <param name="paggerType">分页方式</param>  
        /// <param name="httpMethod">Http请求方式：GET|POST</param>
        /// <returns></returns>
        public static MvcHtmlString Pagger(this HtmlHelper helper, int rowCount, int pageIndex, int pageSize, HttpMethod httpMethod)
        {
            return Pagger(helper, rowCount, pageIndex, pageSize, httpMethod, PageButtonLabel.Default);
        }

        /// <summary>
        /// Html分页扩展方法，使用PrevNext分页方式和GET请求方式
        /// </summary>
        /// <param name="helper">HtmlHelper对象</param>
        /// <param name="rowCount">分页数据的总行数</param>
        /// <param name="pageIndex">当前分页索引，从0开始</param>
        /// <param name="pageSize">每页的显示个数</param>
        /// <param name="paggerType">分页方式</param>  
        /// <param name="buttonLabel">分页按钮Label对象</param>
        /// <returns></returns>
        public static MvcHtmlString Pagger(this HtmlHelper helper, int rowCount, int pageIndex, int pageSize, PageButtonLabel buttonLabel)
        {
            return Pagger(helper, rowCount, pageIndex, pageSize, HttpMethod.GET, buttonLabel);
        }

        /// <summary>
        /// Html分页扩展方法，使用PrevNext分页方式、GET请求方式、默认的分页按钮Label
        /// </summary>
        /// <param name="helper">HtmlHelper对象</param>
        /// <param name="rowCount">分页数据的总行数</param>
        /// <param name="pageIndex">当前分页索引，从0开始</param>
        /// <param name="pageSize">每页的显示个数</param>
        /// <returns></returns>
        public static MvcHtmlString Pagger(this HtmlHelper helper, int rowCount, int pageIndex, int pageSize)
        {
            return Pagger(helper, rowCount, pageIndex, pageSize, HttpMethod.GET, PageButtonLabel.Default);
        }

        #endregion

        #region Image

        /// <summary>
        /// HTML图片控件
        /// </summary>
        /// <param name="helper">HtmlHelper对象</param>
        /// <param name="relativeUrl">图片的相对路径，如：Content/background.png</param>
        /// <param name="htmlAttributes">HTML属性集合</param>
        /// <returns></returns>
        public static MvcHtmlString Image(this HtmlHelper helper, string relativeUrl, object htmlAttributes)
        {
            UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
            string url = relativeUrl.StartsWith("/") ? String.Format("~{0}", relativeUrl) : String.Format("~/{0}", relativeUrl);
            url = urlHelper.Content(url);
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("<img src=\"{0}\" ", url);
            if (htmlAttributes != null)
            {
                string alt = null;
                string title = null;
                foreach (var prop in htmlAttributes.GetType().GetProperties())
                {
                    try
                    {
                        string name = prop.Name;
                        string value = prop.GetValue(htmlAttributes, null).ToString();
                        sb.AppendFormat("{0}=\"{1}\" ", name, value);
                        if (name.ToLower() == "alt")
                        {
                            alt = value;
                        }
                        if (name == "title")
                        {
                            title = value;
                        }
                    }
                    catch
                    {
                    }
                }
                if (alt != null && title == null)
                {
                    sb.AppendFormat("title=\"{0}\"", alt);
                }
                else if (alt == null && title != null)
                {
                    sb.AppendFormat("alt=\"{0}\"", title);
                }
            }
            sb.Append("/>");
            return new MvcHtmlString(sb.ToString());
        }

        /// <summary>
        /// HTML图片控件
        /// </summary>
        /// <param name="helper">HtmlHelper对象</param>
        /// <param name="actionName">获取图片的Action</param>
        /// <param name="controllerName">获取图片的Controller</param>
        /// <param name="routeValues">获取图片的路由参数集合</param>
        /// <param name="htmlAttributes">HTML属性集合</param>
        /// <returns></returns>
        public static MvcHtmlString Image(this HtmlHelper helper, string actionName, string controllerName, object routeValues, IDictionary<string, object> htmlAttributes)
        {
            UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
            string relativeUrl = urlHelper.Action(actionName, controllerName, routeValues);
            return Image(helper, relativeUrl, htmlAttributes);
        }

        /// <summary>
        /// HTML图片控件，使用当前的Controller
        /// </summary>
        /// <param name="helper">HtmlHelper对象</param>
        /// <param name="actionName">获取图片的Action</param>        
        /// <param name="routeValues">获取图片的路由参数集合</param>
        /// <param name="htmlAttributes">HTML属性集合</param>
        /// <returns></returns>
        public static MvcHtmlString Image(this HtmlHelper helper, string actionName, object routeValues, object htmlAttributes)
        {
            UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
            string relativeUrl = urlHelper.Action(actionName, routeValues);
            return Image(helper, relativeUrl, htmlAttributes);
        }

        #endregion

        #region Upload

        private static MvcHtmlString DoUpload(HtmlHelper helper, string relativeUrl, UploadOptions options)
        {
            UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
            string url = urlHelper.Content(relativeUrl);
            int index = GetUploadElementIndex(helper.ViewContext);
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("<script type=\"text/javascript\">");

            sb.AppendLine("</script>");

            string idOrName = String.Format("fileToUpload{0}", index);
            //sb.AppendLine("<div style=\"display:none;\">");
            sb.AppendLine("<input id=\"" + idOrName + "\" type=\"file\" name=\"" + idOrName + "\"/>");
            //sb.AppendLine("</div>");
            sb.AppendLine("<input type=\"button\" value=\"" + options.ButtonLabel + "\" onclick=\"upload('" + url + "','" + idOrName + "'," + options.OnSuccess + "," + options.OnCompleted + "," + options.OnError + ");\"/>");
            return new MvcHtmlString(sb.ToString());
        }

        public static MvcHtmlString Upload(this HtmlHelper helper, string actionName, string controllerName, object routeValues, UploadOptions options)
        {
            UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
            string url = urlHelper.Action(actionName, controllerName, routeValues);
            return DoUpload(helper, url, options);
        }

        public static MvcHtmlString Upload(this HtmlHelper helper, string actionName, object routeValues, UploadOptions options)
        {
            UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
            string url = urlHelper.Action(actionName, routeValues);
            return DoUpload(helper, url, options);
        }

        public static MvcHtmlString Upload(this HtmlHelper helper, string actionName, UploadOptions options)
        {
            UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
            string url = urlHelper.Action(actionName);
            return DoUpload(helper, url, options);
        }

        private static int GetUploadElementIndex(ViewContext viewContext)
        {
            int index = 0;
            if (viewContext.HttpContext.Items["uploadId"] != null)
            {
                index = Convert.ToInt32(viewContext.HttpContext.Items["uploadId"]);
            }
            viewContext.HttpContext.Items["uploadId"] = ++index;
            return index;
        }

        #endregion
    }

    public sealed class UploadOptions
    {
        public UploadOptions()
        {
            this.ButtonLabel = "Upload";            
            this.OnSuccess = "null";
            this.OnCompleted = "null";
            this.OnError = "null";
        }

        public string ButtonLabel { get; set; }

        public string OnSuccess { get; set; }

        public string OnCompleted { get; set; }

        public string OnError { get; set; }
    }
}
